package jwt

import (
	"errors"
	"time"

	"github.com/spf13/viper"

	"github.com/dgrijalva/jwt-go"
)

// TokenExpireDuration 定义 JWT 的过期时间
//const TokenExpireDuration = time.Hour * 2 * 24 * 365

// MySecret 定义 Secret
var MySecret = []byte("长风破浪会有时，直挂云帆济沧海")

// MyClaims 自定义声明结构体并内嵌jwt.StandardClaims
// jwt包自带的jwt.StandardClaims只包含了官方字段
// 我们这里需要额外记录一个username字段，所以要自定义结构体
// 如果想要保存更多信息，都可以添加到这个结构体中
type MyClaims struct {
	UserID   int64  `json:"user_id"`
	Username string `json:"username"`
	jwt.StandardClaims
}

// GetToken 生成 JWT
func GetToken(userID int64, username string) (string, error) {
	//创建一个我们自己的声明
	c := MyClaims{
		UserID:   userID,
		Username: username, //自定义字段
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Duration(viper.GetInt("auth.jwt_expire")) * time.Hour).Unix(), //过期时间
			Issuer:    "bluebell",                                                                        //签发人
		},
	}
	//使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	//使用指定的 Secret 签名并获得完整的编码后的字符串 token
	return token.SignedString(MySecret)
}

// ParseToken 解析 JWT
func ParseToken(tokenString string) (*MyClaims, error) {
	//解析 token
	var mc = new(MyClaims)
	/*token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return MySecret, nil
	})*/
	token, err := jwt.ParseWithClaims(tokenString, mc, func(token *jwt.Token) (interface{}, error) {
		return MySecret, nil
	})

	if err != nil {
		return nil, err
	}
	/*if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { //校验 token
		return claims, nil
	}*/
	if token.Valid { //校验 token
		return mc, nil
	}
	return nil, errors.New("invalid token")
}

//--------------- 基于 JWT 实现认证实践 -----------------------

// GenToken 生成 access token 和 refresh token
//func GenToken(userID int64) (aToken, rToken string, err error) {
//	//创建一个我们自己的声明
//	c := MyClaims{
//		UserID: userID, //自定义字段
//		StandardClaims: jwt.StandardClaims{
//			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), //过期时间
//			Issuer:    "bluebell",
//		},
//	}
//	//加密并获得完整的编码后的字符串 Token
//	aToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString(MySecret)
//
//	//refresh token 不需要任何自定义数据（只有在刷新数据的时候才会用到它）
//	rToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
//		ExpiresAt: time.Now().Add(time.Second * 30).Unix(), //过期时间
//		Issuer:    "blubell",                               //签发人
//	}).SignedString(MySecret)
//
//	//使用指定的 secret 签名并获得完整的编码后的字符串 token
//	return
//}

//
//// ParseToken01 解析 JWT
//func ParseToken01(tokenString string) (claims *MyClaims, err error) {
//	//解析 token
//	var token *jwt.Token
//	claims = new(MyClaims)
//	token, err = jwt.ParseWithClaims(tokenString, claims, KeyFunc)
//	if err != nil {
//		return
//	}
//	if !token.Valid { //校验 token
//		err = errors.New("invalid token")
//	}
//	return
//}
//
//// RefreshToken 刷新 AccessToken
//func RefreshToken(aToken, rToken string) (newAToken, newRToken string, err error) {
//	//refresh token 无效直接返回
//	if _, err = jwt.Parse(rToken, keyFunc); err != nil {
//		return
//	}
//
//	//从旧 Access Token 中解析出 claims 数据
//	var claims MyClaims
//	_, err = jwt.ParseWithClaims(aToken, &claims, keyFunc)
//	v, _ := err.(*jwt.ValidationError)
//
//	//当 Access Token 是过期错误 并且 refresh token 没有过期时，就创建一个新的 Access Token
//	if v.Errors == jwt.ValidationErrorExpired {
//		return GenToken(claims.UserID)
//	}
//	return
//}
